#region Using References

using System;
using System.Diagnostics.Contracts;
using System.Linq;
using Beaker.Services.FileSystem.Physical;
using Beaker.Services.FileSystem.Zip;
using Microsoft.Practices.ServiceLocation;
using ServiceLocator = Beaker.Services.Locator.ServiceLocator;

#endregion

namespace Beaker.Services.FileSystem
{
	public static class FileSystemService
	{
		private static readonly Physical.FileSystemService _default = new Physical.FileSystemService();

		public static IFileSystemService Default
		{
			get
			{
				Contract.Ensures( Contract.Result<IFileSystemService>() != null );
				return ServiceLocator.Provide<IFileSystemService>( _default );
			}
		}

		private static readonly FileSystemServiceProvider _defaultProvider
			= new FileSystemServiceProvider();

		public static IFileSystemServiceProvider DefaultProvider
		{
			get
			{
				return ServiceLocator.Provide( _defaultProvider );
			}
		}

		public static IFileSystemService FromFile( IFile file )
		{
			Contract.Requires<ArgumentNullException>( file != null );

			IFileSystemServiceProvider[] services = null;

			// try to get all instances from locator
			IServiceLocator locator = ServiceLocator.Current;
			if( locator != null )
				services = locator.GetAllInstances<IFileSystemServiceProvider>().ToArray();

			// if not, then use the default
			if( services == null )
				services = new IFileSystemServiceProvider[] { new FileSystemServiceProvider(), new ZipFileSystemServiceProvider() };

			// loop over all services until we find one that can handle it
			foreach( IFileSystemServiceProvider service in services )
			{
				IFileSystemService result = service.FromFile( file );
				if( result != null )
					return result;
			}

			// nothing can handle it, so send null
			return null;
		}

		/// <summary>
		/// Wrap the file if there is a provider that supplies a filesystem for the file
		/// </summary>
		/// <param name="file">The file to try to wrap.</param>
		/// <returns>The wrapped file, or the original file.</returns>
		public static IFile WrapIfProvided( this IFile file )
		{
			if( file == null )
				return null;
			
			var wrappedFile = FromFile( file ) as IFile;
			if( wrappedFile != null )
				return wrappedFile;

			return file;
		}
	}
}